#include <iostream>
#include <fstream>
#include <string>

#include <unistd.h>
#include <errno.h>
#include <vector>

#include "XBaseClient.h"
#include "XBaseCommand.h"

#ifdef LOGGER
#include <log4cplus/logger.h>
#include <log4cplus/configurator.h>
#include <log4cplus/tstring.h>
#endif

using namespace std;

string gTableName;
string gMasterIP;
int gMasterPort = 20081;

static size_t split(std::vector<std::string>& result, const std::string & str, const char sp)
{
	size_t startPos = 0;
	size_t endPos = 0;
	while ( (endPos = str.find( sp, startPos )) != std::string::npos ) {
		if ( (endPos - startPos) > 0 ) {
			result.push_back( str.substr( startPos, (endPos - startPos) ) );
		}

		startPos = endPos + 1;
	}
	if ( !str.empty() && startPos <= (str.length () - 1) ) {
		result.push_back( str.substr (startPos) );
	}

	return result.size();
}

struct SDUrlInfo
{
	std::string fileUrlNoUP;
	std::string fileSuffix;
	std::string contentID;
	std::string fileSize;
	std::string fullContentID;
	std::string fullCIDType;
	std::string fullCIDVerifyTimes;
	std::string fullCIDConflictTimes;
	std::string fullCIDPartSize;
	std::string queryFlag;
	std::string lastModified;

	friend std::ifstream& operator>> ( std::ifstream& in, SDUrlInfo& urlInfo );
	friend std::ostream& operator<< ( std::ostream& out, const SDUrlInfo& urlInfo );
};

std::ifstream& operator>> ( std::ifstream& in, SDUrlInfo& urlInfo )
{	
	std::string line;
	if ( !( (std::getline( in, line )).fail() ) ) {
		std::vector<std::string> columns;
		size_t columnCount = split( columns, line, '\t' );
		if ( columnCount != 11 ) {
			std::cout << "columnCount ne 10" << std::endl;
		} else {
			int idx = 0;
			urlInfo.fileUrlNoUP = columns[idx++];
			urlInfo.fileSuffix = columns[idx++];
			urlInfo.contentID = columns[idx++];
			urlInfo.fileSize = columns[idx++];
			urlInfo.fullContentID = columns[idx++];
			urlInfo.fullCIDType = columns[idx++];
			urlInfo.fullCIDVerifyTimes = columns[idx++];
			urlInfo.fullCIDConflictTimes = columns[idx++];
			urlInfo.fullCIDPartSize = columns[idx++];
			urlInfo.queryFlag = columns[idx++];
			urlInfo.lastModified = columns[idx++];
		}
	}

	return in;
}

std::ostream& operator<< ( std::ostream& out, const SDUrlInfo& urlInfo )
{
	out << "fileUrlNoUP" << "\t" << urlInfo.fileUrlNoUP << "\n"
		<< "fileSuffix" << "\t" << urlInfo.fileSuffix << "\n"
		<< "contentID" << "\t" << urlInfo.contentID << "\n"
		<< "fileSize" << "\t" << urlInfo.fileSize << "\n"
		<< "fullContentID" << "\t" << urlInfo.fullContentID << "\n"
		<< "fullCIDType" << "\t" << urlInfo.fullCIDType << "\n"
		<< "fullCIDVerifyTimes" << "\t" << urlInfo.fullCIDVerifyTimes << "\n"
		<< "fullCIDConflictTimes" << "\t" << urlInfo.fullCIDConflictTimes << "\n"
		<< "fullCIDPartSize" << "\t" << urlInfo.fullCIDPartSize << "\n"
		<< "queryFlag" << "\t" << urlInfo.queryFlag << "\n"
		<< "lastModified" << "\t" << urlInfo.lastModified;

	return out;
}

void test_insert(const std::string& data_filename)
{
	XBaseClient cn( gMasterIP.c_str(), gMasterPort );
	cn.set_recv_timeout( 3600*1000 );
	cn.set_send_timeout( 3600*1000 );

	std::ifstream in( data_filename.c_str() );
	if ( in.fail() ) {
		std::cerr << "open " << data_filename << " fail. errno " << errno << std::endl;
		return;
	}

	const int BUFSIZE = 1024;
	char buffer[ BUFSIZE ];	

	int row = 1;
	SDUrlInfo urlInfo;
	while ( !( in >> urlInfo ).fail() ) {

		std::cout << "*************************** " << (row++) << ". row ***************************" << std::endl;
		std::cout << urlInfo << std::endl;

		XBaseCommandInsert cmd;
		cmd.set_table_name( gTableName );

		//urlInfo.contentID = Utility::hex_2_str( urlInfo.contentID );
		//urlInfo.fullContentID = Utility::hex_2_str( urlInfo.fullContentID );

		snprintf( buffer, sizeof(buffer), "cid:" );
		cmd.add( urlInfo.contentID, urlInfo.fileUrlNoUP, buffer );

		snprintf( buffer, sizeof(buffer), "info:fileSuffix" );
		cmd.add( urlInfo.fileSuffix, urlInfo.fileUrlNoUP, buffer );
		snprintf( buffer, sizeof(buffer), "info:contentID" );
		cmd.add( urlInfo.contentID, urlInfo.fileUrlNoUP, buffer );
		snprintf( buffer, sizeof(buffer), "info:fileSize" );
		cmd.add( urlInfo.fileSize, urlInfo.fileUrlNoUP, buffer );
		snprintf( buffer, sizeof(buffer), "info:fullContentID" );
		cmd.add( urlInfo.fullContentID, urlInfo.fileUrlNoUP, buffer );
		snprintf( buffer, sizeof(buffer), "info:fullCIDType" );
		cmd.add( urlInfo.fullCIDType, urlInfo.fileUrlNoUP, buffer );
		snprintf( buffer, sizeof(buffer), "info:fullCIDVerifyTimes" );
		cmd.add( urlInfo.fullCIDVerifyTimes, urlInfo.fileUrlNoUP, buffer );
		snprintf( buffer, sizeof(buffer), "info:fullCIDConflictTimes" );
		cmd.add( urlInfo.fullCIDConflictTimes, urlInfo.fileUrlNoUP, buffer );
		snprintf( buffer, sizeof(buffer), "info:fullCIDPartSize" );
		cmd.add( urlInfo.fullCIDPartSize, urlInfo.fileUrlNoUP, buffer );
		snprintf( buffer, sizeof(buffer), "info:queryFlag" );
		cmd.add( urlInfo.queryFlag, urlInfo.fileUrlNoUP, buffer );
		snprintf( buffer, sizeof(buffer), "info:lastModified" );
		cmd.add( urlInfo.lastModified, urlInfo.fileUrlNoUP, buffer );

		//continue;

		cn.execute( &cmd );		
		if ( cmd.fail() ) {
			std::cout << cmd.errorstr() << std::endl;
		}
		else {
			std::cout << std::endl << "Query OK, " << cmd.affected_rows() << " rows affected" << std::endl;
		}

		//std::cout << cmd.to_string() << std::endl;
	}	
}

int main(int argc, char* argv[])
{	
	#ifdef LOGGER
	log4cplus::PropertyConfigurator::doConfigure("../conf/log4cplus.properties");
	#endif

	string filename;

	extern char *optarg;
	extern int optopt;

	char c;
	 while ( (c = getopt( argc, argv, ":h:p:t:f:" ) ) != -1 ) {
	 	switch( c ) {
			case 'h':
				gMasterIP = optarg; 
				break;
			case 'p':
				gMasterPort = atoi ( optarg );
				break;
			case 't':
				gTableName = optarg;
				break;
			case 'f':
				filename = optarg;
				break;
			case ':':       /* without operand */
				fprintf(stderr, "Option -%c requires an operand\n", optopt);    
				exit( EXIT_FAILURE );
				break;
			case '?':
				fprintf(stderr, "Unrecognized option: -%c\n", optopt);
				exit( EXIT_FAILURE );
				break;
		}
	}

	 if ( gMasterIP.empty() || gTableName.empty() ) {
	 	cerr << "Usage: " << argv[0] << " -h 192.168.3.217 -p 20081 -t sd_url_info -f sd_url_info_0.data" << endl;
	 	exit( EXIT_FAILURE );
	 }
	 
	test_insert( filename );
}
